package system.track;

/**
 * This class provides a code representation of the train track, made up
 * of Blocks, Switches, and Sensors, just as the physical track is.  The
 * Track class can be altered if any physical tracks are rearranged.
 * 
 * @author David
 * @version Cycle 1 - complete
 */
public class Track
{
    //startPoints are provided for each of the possible two trains
    private Block startPoint1;
    private Block startPoint2;

    /**
     * Constructor for Objects of class Track.  Creates a train Track
     * with all appropriate Blocks, Switches, and Sensors, logically
     * linked.
     */
    public Track()
    {
        Block[] blocks = new Block[10];
        Switch[] switches = new Switch[7];
        Sensor[] sensors = new Sensor[15];

        //create the Sensors with ID's; each one is a GenericSensor
        for (int i = 1; i < sensors.length; i++)
        {
            sensors[i] = new GenericSensor();
            sensors[i].setID(i);
        }

        //create the Switches with ID's; note that each will be 
        //initially set to 180 degrees
        for (int i = 1; i < switches.length; i++)
        {
            switches[i] = new GenericSwitch();
            switches[i].setID(i);
        }

        //create Block 1, and attach Sensors and Switches
        blocks[1] = new GenericBlock();
        blocks[1].setID(1);
        blocks[1].addSensor(Direction.CLOCKWISE, sensors[1]);
        blocks[1].addSensor(Direction.CLOCKWISE, sensors[2]);
        blocks[1].addSensor(Direction.COUNTERCLOCKWISE, sensors[5]);
        blocks[1].addSensor(Direction.COUNTERCLOCKWISE, sensors[6]);
        blocks[1].setSwitch(Direction.CLOCKWISE, switches[1]);
        blocks[1].setSwitch(Direction.COUNTERCLOCKWISE, switches[3]);

        //connecting Switches to the appropriate Blocks
        switches[1].setEntrance(blocks[1]);
        switches[3].setEntrance(blocks[1]);

        //create Block 2, another GenericBlock
        blocks[2] = new GenericBlock();
        blocks[2].setID(2);
        blocks[2].addSensor(Direction.CLOCKWISE, sensors[9]);
        blocks[2].addSensor(Direction.CLOCKWISE, sensors[10]);
        blocks[2].addSensor(Direction.COUNTERCLOCKWISE, sensors[1]);
        blocks[2].setSwitch(Direction.CLOCKWISE, switches[5]);
        blocks[2].setSwitch(Direction.COUNTERCLOCKWISE, switches[1]);

        //connecting Switches to the appropriate Blocks
        switches[1].setExit(SwitchAngle.ONE_EIGHTY_DEGREES, blocks[2]);
        switches[5].setEntrance(blocks[2]);

        //create Block 3, another GenericBlock
        blocks[3] = new GenericBlock();
        blocks[3].setID(3);
        blocks[3].addSensor(Direction.CLOCKWISE, sensors[4]);
        blocks[3].addSensor(Direction.COUNTERCLOCKWISE, sensors[3]);
        blocks[3].setSwitch(Direction.CLOCKWISE, null);
        blocks[3].setSwitch(Direction.COUNTERCLOCKWISE, switches[2]);

        //connecting Switches to the appropriate Blocks
        switches[2].setExit(SwitchAngle.NINETY_DEGREES, blocks[3]);

        //create Block 4, a special Block of class Block4
        Block4 block4 = new Block4();
        block4.setID(4);
        block4.addSensor(Direction.COUNTERCLOCKWISE, sensors[11]);
        block4.addSensor(Direction.CLOCKWISE, sensors[2]);
        block4.setSwitch(Direction.COUNTERCLOCKWISE, switches[6]);
        block4.setSwitch(Direction.CLOCKWISE, switches[1]);

        //connecting Switches to the appropriate Blocks
        switches[1].setExit(SwitchAngle.NINETY_DEGREES, block4);
        switches[6].setExit(SwitchAngle.NINETY_DEGREES, block4);
        switches[2].setExit(SwitchAngle.ONE_EIGHTY_DEGREES, block4);
        switches[4].setExit(SwitchAngle.ONE_EIGHTY_DEGREES, block4);
        switches[2].setEntrance(block4);
        switches[4].setEntrance(block4);

        //set the parking block settings for Block 4
        block4.setParkingBlock(Direction.COUNTERCLOCKWISE, blocks[3]);
        block4.setParkingSwitch(Direction.COUNTERCLOCKWISE, switches[2]);
        block4.setParkingSwitch(Direction.CLOCKWISE, switches[4]);
        blocks[4] = block4;

        //create Block5, a new GenericBlock
        blocks[5] = new GenericBlock();
        blocks[5].setID(5);
        blocks[5].setSwitch(Direction.COUNTERCLOCKWISE, switches[4]);
        blocks[5].setSwitch(Direction.CLOCKWISE, null);
        blocks[5].addSensor(Direction.COUNTERCLOCKWISE, sensors[13]);
        blocks[5].addSensor(Direction.CLOCKWISE, sensors[8]);

        //connecting Switches to the appropriate Blocks
        switches[4].setExit(SwitchAngle.ONE_EIGHTY_DEGREES, blocks[5]);

        //set the parking block settings for Block 4
        block4.setParkingBlock(Direction.CLOCKWISE, blocks[5]);

        //create Block 6, a GenericBlock
        blocks[6] = new GenericBlock();
        blocks[6].setID(6);
        blocks[6].setSwitch(Direction.COUNTERCLOCKWISE, switches[6]);
        blocks[6].setSwitch(Direction.CLOCKWISE, switches[3]);
        blocks[6].addSensor(Direction.CLOCKWISE, sensors[5]);
        blocks[6].addSensor(Direction.COUNTERCLOCKWISE, sensors[12]);

        //connecting Switches to the appropriate Blocks
        switches[3].setExit(SwitchAngle.NINETY_DEGREES, blocks[6]);
        switches[6].setExit(SwitchAngle.ONE_EIGHTY_DEGREES, blocks[6]);

        //create Block 7, a GenericBlock
        blocks[7] = new GenericBlock();
        blocks[7].setID(7);
        blocks[7].setSwitch(Direction.COUNTERCLOCKWISE, switches[5]);
        blocks[7].setSwitch(Direction.CLOCKWISE, switches[6]);
        blocks[7].addSensor(Direction.COUNTERCLOCKWISE, sensors[9]);
        blocks[7].addSensor(Direction.CLOCKWISE, sensors[11]);
        blocks[7].addSensor(Direction.CLOCKWISE, sensors[12]);

        //connecting Switches to the appropriate Blocks
        switches[6].setEntrance(blocks[7]);
        switches[5].setExit(SwitchAngle.NINETY_DEGREES, blocks[7]);

        //create Blocks 8 and 9, each of which has its own class type
        Block8 block8 = new Block8();
        Block9 block9 = new Block9();

        //connect Block 8 to Block 9
        block8.setCCWBlock(block9);
        block9.setCWBlock(block8);

        blocks[8] = block8;
        blocks[9] = block9;

        //continue creating Block 8
        blocks[8].setID(8);
        blocks[8].setSwitch(Direction.CLOCKWISE, switches[3]);
        blocks[8].addSensor(Direction.COUNTERCLOCKWISE, sensors[14]);
        blocks[8].addSensor(Direction.CLOCKWISE, sensors[6]);

        //connecting Switches to the appropriate Blocks
        switches[3].setExit(SwitchAngle.ONE_EIGHTY_DEGREES, blocks[8]);

        //continue creating Block 9
        blocks[9].setID(9);
        blocks[9].setSwitch(Direction.COUNTERCLOCKWISE, switches[5]);
        blocks[9].addSensor(Direction.CLOCKWISE, sensors[14]);
        blocks[9].addSensor(Direction.COUNTERCLOCKWISE, sensors[10]);

        //connecting Switches to the appropriate Blocks
        switches[5].setExit(SwitchAngle.ONE_EIGHTY_DEGREES, blocks[9]);

        //set start points for two possible trains
        this.startPoint1 = blocks[1];
        this.startPoint2 = blocks[5];
    }

    /**
     * Returns the starting Block location as a reference for the creation
     * of trains (which always start at a specific location), and for the
     * creation of Routes.
     * 
     * @param d the ID of the startPoint to return; 1 or 2
     * @return  a Block where a train will be starting
     */
    public Block getStartPoint(int id)
    {
        Block returnVal = this.startPoint1;
        if (id == 2)
        {
            returnVal = this.startPoint2;
        }
        if(id > 2)
        {
            throw new IllegalArgumentException("Bad start point id.");
        }
        return returnVal;
    }
}